{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 探索 name_scope 和 variable_scope"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[TensorFlow 变量共享，命名空间](https://blog.csdn.net/jacke121/article/details/77622834)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "v1.name:  nsc1/v1:0\n",
      "v2.name:  nsc1/vsc1/v2:0\n",
      "v3.name:  vsc1/v3:0\n",
      "v4.name:  nsc1_1/v4:0\n"
     ]
    }
   ],
   "source": [
    "import tensorflow as tf\n",
    "# 设置GPU按需增长\n",
    "config = tf.ConfigProto()\n",
    "config.gpu_options.allow_growth = True\n",
    "sess = tf.Session(config=config)\n",
    "\n",
    "with tf.name_scope('nsc1'):\n",
    "    v1 = tf.Variable([1], name='v1')\n",
    "    with tf.variable_scope('vsc1'):\n",
    "        v2 = tf.Variable([1], name='v2')\n",
    "        v3 = tf.get_variable(name='v3', shape=[])\n",
    "print('v1.name: ', v1.name)\n",
    "print('v2.name: ', v2.name)\n",
    "print('v3.name: ', v3.name)\n",
    "\n",
    "with tf.name_scope('nsc1'):\n",
    "    v4 = tf.Variable([1], name='v4')\n",
    "print('v4.name: ', v4.name)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- tf.name_scope() 并不会对 tf.get_variable() 创建的变量有任何影响。 \n",
    "- tf.name_scope() 主要是用来管理命名空间的，这样子让我们的整个模型更加有条理。\n",
    "- 而 tf.variable_scope() 的作用是为了实现变量共享，它和 tf.get_variable() 来完成变量共享的功能。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "第一组，用 tf.Variable() 的方式来定义"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "There are 8 train_able_variables in the Graph: \n",
      "<tf.Variable 'conv1_weights:0' shape=(5, 5, 32, 32) dtype=float32_ref>\n",
      "<tf.Variable 'conv1_biases:0' shape=(32,) dtype=float32_ref>\n",
      "<tf.Variable 'conv2_weights:0' shape=(5, 5, 32, 32) dtype=float32_ref>\n",
      "<tf.Variable 'conv2_biases:0' shape=(32,) dtype=float32_ref>\n",
      "<tf.Variable 'conv1_weights_1:0' shape=(5, 5, 32, 32) dtype=float32_ref>\n",
      "<tf.Variable 'conv1_biases_1:0' shape=(32,) dtype=float32_ref>\n",
      "<tf.Variable 'conv2_weights_1:0' shape=(5, 5, 32, 32) dtype=float32_ref>\n",
      "<tf.Variable 'conv2_biases_1:0' shape=(32,) dtype=float32_ref>\n"
     ]
    }
   ],
   "source": [
    "import tensorflow as tf\n",
    "# 设置GPU按需增长\n",
    "tf.reset_default_graph()\n",
    "config = tf.ConfigProto()\n",
    "config.gpu_options.allow_growth = True\n",
    "sess = tf.Session(config=config)\n",
    "\n",
    "# 拿官方的例子改动一下\n",
    "def my_image_filter():\n",
    "    conv1_weights = tf.Variable(tf.random_normal([5, 5, 32, 32]),name=\"conv1_weights\")\n",
    "    conv1_biases = tf.Variable(tf.zeros([32]), name=\"conv1_biases\")\n",
    "    conv2_weights = tf.Variable(tf.random_normal([5, 5, 32, 32]),name=\"conv2_weights\")\n",
    "    conv2_biases = tf.Variable(tf.zeros([32]), name=\"conv2_biases\")\n",
    "    return None\n",
    "\n",
    "# First call creates one set of 4 variables.\n",
    "result1 = my_image_filter()\n",
    "# Another set of 4 variables is created in the second call.\n",
    "result2 = my_image_filter()\n",
    "# 获取所有的可训练变量\n",
    "vs = tf.trainable_variables()\n",
    "print('There are %d train_able_variables in the Graph: ' % len(vs))\n",
    "for v in vs:\n",
    "    print(v)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "第二种方式，用 tf.get_variable() 的方式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<tensorflow.python.ops.variable_scope.VariableScope object at 0x000000001431BEF0>\n",
      "There are 4 train_able_variables in the Graph: \n",
      "<tf.Variable 'image_filters/conv1/weights:0' shape=(5, 5, 32, 32) dtype=float32_ref>\n",
      "<tf.Variable 'image_filters/conv1/biases:0' shape=(32,) dtype=float32_ref>\n",
      "<tf.Variable 'image_filters/conv2/weights:0' shape=(5, 5, 32, 32) dtype=float32_ref>\n",
      "<tf.Variable 'image_filters/conv2/biases:0' shape=(32,) dtype=float32_ref>\n"
     ]
    }
   ],
   "source": [
    "import tensorflow as tf\n",
    "tf.reset_default_graph()\n",
    "# 设置GPU按需增长\n",
    "config = tf.ConfigProto()\n",
    "config.gpu_options.allow_growth = True\n",
    "sess = tf.Session(config=config)\n",
    "\n",
    "# 下面是定义一个卷积层的通用方式\n",
    "def conv_relu(kernel_shape, bias_shape):\n",
    "    # Create variable named \"weights\".\n",
    "    weights = tf.get_variable(\"weights\", kernel_shape, initializer=tf.random_normal_initializer())\n",
    "    # Create variable named \"biases\".\n",
    "    biases = tf.get_variable(\"biases\", bias_shape, initializer=tf.constant_initializer(0.0))\n",
    "    return None\n",
    "\n",
    "\n",
    "def my_image_filter():\n",
    "    # 按照下面的方式定义卷积层，非常直观，而且富有层次感\n",
    "    with tf.variable_scope(\"conv1\"):\n",
    "        # Variables created here will be named \"conv1/weights\", \"conv1/biases\".\n",
    "        relu1 = conv_relu([5, 5, 32, 32], [32])\n",
    "    with tf.variable_scope(\"conv2\"):\n",
    "        # Variables created here will be named \"conv2/weights\", \"conv2/biases\".\n",
    "        return conv_relu( [5, 5, 32, 32], [32])\n",
    "\n",
    "\n",
    "with tf.variable_scope(\"image_filters\") as scope:\n",
    "    # 下面我们两次调用 my_image_filter 函数，但是由于引入了 变量共享机制\n",
    "    # 可以看到我们只是创建了一遍网络结构。\n",
    "    result1 = my_image_filter()\n",
    "    # 通过 reuse_variables() 共享变量\n",
    "    scope.reuse_variables()\n",
    "    result2 = my_image_filter()\n",
    "\n",
    "\n",
    "# 看看下面，完美地实现了变量共享！！！\n",
    "vs = tf.trainable_variables()\n",
    "print('There are %d train_able_variables in the Graph: ' % len(vs))\n",
    "for v in vs:\n",
    "    print(v)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 结论\n",
    "首先我们要确立一种 Graph 的思想。在 TensorFlow 中，我们定义一个变量，相当于往 Graph 中添加了一个节点。和普通的 Python 函数不一样，在一般的函数中，我们对输入进行处理，然后返回一个结果，而函数里边定义的一些局部变量我们就不管了。但是在 TensorFlow 中，我们在函数里边创建了一个变量，就是往 Graph 中添加了一个节点。出了这个函数后，这个节点还是存在于 Graph 中的。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda root]",
   "language": "python",
   "name": "conda-root-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
